/**************************************************************************
 //* W Corp. 
 //* W Profile Services                                             
 //* Package:  by.doubleyou.monitor.peer
 //* (C) Copyright W Corp.  2007
  *  (C) SUN. CDDL lic 2007
  */
 /**************************************************************************
 *
 * Copyright (c) 2007, W Corporation
 * All rights reserved.
 * 
 * Version: 1.0
 * Date:  3 Dec, 2007, Author: Alexander J. Perez Tchernov
 * 
 * MODIFICATION HISTORY:
 * Defect/Feature  	Description
 * ---
 */
package by.doubleyou.core.gms;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import by.doubleyou.monitor.peer.AgregatorService;
import by.doubleyou.monitor.peer.StorageService;

import com.sun.enterprise.ee.cms.core.GMSConstants;
import com.sun.enterprise.ee.cms.core.GMSException;
import com.sun.enterprise.ee.cms.core.GMSFactory;
import com.sun.enterprise.ee.cms.core.GroupHandle;
import com.sun.enterprise.ee.cms.core.GroupManagementService;
import com.sun.enterprise.ee.cms.core.ServiceProviderConfigurationKeys;
import com.sun.enterprise.ee.cms.impl.common.GroupManagementServiceImpl;
import com.sun.enterprise.ee.cms.logging.GMSLogDomain;
import com.sun.enterprise.jxtamgmt.JxtaUtil;

/**
 * Load balancer
 * 
 * @author Alexander J. Perez Tchernov
 * @author GlassFish Shoal Team
 * 
 */
public class GMSPeerServer implements Runnable {
    private static final Logger logger = GMSLogDomain.getLogger(GMSLogDomain.GMS_LOGGER);
    static {
    	logger.setLevel(Level.INFO);
    }

    private GroupManagementService gms;
    
    //TODO SEVERE list of clients
    private GMSClientService gcs1, gcs2;
    private String serverName;
    private String groupName;

    /**
     * Constructor
     * 
     * @param serverName  instanceToken
     * @param groupName   gmsGroupName
     * @param memberType  CORE or SPECTATOR
     * @param props       parameters
     */
    public GMSPeerServer(final String serverName, final String groupName,
                             final GroupManagementService.MemberType memberType,
                             final Properties props) {
        this.serverName = serverName;
        this.groupName = groupName;
        gms = (GroupManagementService) GMSFactory.startGMSModule(serverName, groupName, memberType, props);
        initClientServices(Boolean.valueOf(System.getProperty("MESSAGING_MODE", "true")));
    }

    private void initClientServices(boolean sendMessages) {    	 
    		gcs1 = new AgregatorService("w-agregator", serverName, sendMessages);    	
    		gcs2 = new StorageService("w-storage", serverName, sendMessages); //Storage Service
    }

/*    private static void setupLogHandler() {
          final ConsoleHandler consoleHandler = new ConsoleHandler();
          try {
              consoleHandler.setLevel(Level.ALL);
              consoleHandler.setFormatter(new NiceLogFormatter());
          } catch( SecurityException e ) {
              new ErrorManager().error(
                   "Exception caught in setting up ConsoleHandler ",
                   e, ErrorManager.GENERIC_FAILURE );
          }
          logger.addHandler(consoleHandler);
          logger.setUseParentHandlers(false);
          final String level = System.getProperty("LOG_LEVEL","FINEST");
          logger.setLevel(Level.parse(level));
      }*/
    
    public void run() {
        startGMS();
        addMemberDetails();
        startClientServices();
        gms.reportJoinedAndReadyState(groupName);
        logger.log(Level.FINE,"reporting joined and ready state...");
        try {
        	String time = System.getProperty("LIFEINMILLIS");
            if(time!=null)
            	Thread.sleep(Integer.parseInt(time));
            else 
            	Thread.currentThread().join();
            
        } catch (InterruptedException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage());
        }
        stopClientServices();
        stopGMS();
        System.exit(0);
    }

    /*
     * Configuration of client services to bind to GMS
     */
    private void addMemberDetails() {
        final Map<Object, Object> details = new Hashtable<Object, Object>();
        final ArrayList<ArrayList> ar1 = new ArrayList<ArrayList>();
        final ArrayList<String> serviceConfigParameters = new ArrayList<String>();
        final int port = 3700;
		final int port1 = 3800;
        try {
            serviceConfigParameters.add(InetAddress.getLocalHost() + ":" + port);
			serviceConfigParameters.add(InetAddress.getLocalHost() + ":" + port1);
        }
        catch (UnknownHostException e) {
            logger.log(Level.WARNING, e.getLocalizedMessage());
        }
        ar1.add(serviceConfigParameters);
        details.put(GMSClientService.IIOP_MEMBER_DETAILS_KEY, ar1);
        try {
            ((GroupManagementServiceImpl) gms).setMemberDetails(serverName, details);
        }
        catch (GMSException e) {
            logger.log(Level.WARNING, e.getLocalizedMessage());
        }
    }

    public void startClientServices() {
        logger.log(Level.FINE, "LoadBalancerPeer: Starting GMSClient");
        //TODO register and iterate
        //TODO visitor pattern
        //TODO gms.getGroupHandle().isGroupLeader()
        //TODO register fix factory to startup service from Slave
        if(System.getProperty("MESSAGING_MODE", "false").equals("true"))
        	gcs1.start();
        gcs2.start();
    }

    public void startGMS() {
        logger.log(Level.FINE, "LoadBalancerPeer: Starting GMS");
        final Thread gservice = new Thread((Runnable) gms, "GMSThread");
        gservice.start();

        try {
            gservice.join();//wait for this thread to die
        } catch (InterruptedException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage());
        }
    }

    public void stopGMS() {
        logger.log(Level.FINE, "LoadBalancerPeer: Stopping GMS");
        gms.shutdown(GMSConstants.shutdownType.INSTANCE_SHUTDOWN);
    }

    private void stopClientServices() {
        logger.log(Level.FINE, "LoadBalancerPeer: Stopping GMSClient");
        gcs1.stopClient();
        gcs2.stopClient();
    }

    public void sendMessage(final String message) {
        final GroupHandle gh = gms.getGroupHandle();
        try {
            gh.sendMessage("w-storage", message.getBytes());
        } catch (GMSException e) {
            logger.log(Level.INFO, e.getLocalizedMessage());
        }
    }

    /**
     * Method to invoke GMS PEER Server
     * 
     * @param args
     */
    public static void main(final String[] args) {
    	logger.setLevel(Level.WARNING);
        if (args.length > 0 && "--usage".equals(args[1])) {
            logger.log(Level.INFO, new StringBuffer().append("USAGE: java -DMEMBERTYPE <CORE|SPECTATOR>")
                    .append(" -DINSTANCEID=<instanceid>")
                    .append(" -DCLUSTERNAME=<clustername")
                    .append(" -DLIFEINMILLIS= <length of time for this demo")
                    .append(" -DMESSAGING_MODE=[true|false] ApplicationServer")
                    .toString());
        }
        JxtaUtil.setLogger(logger);
        JxtaUtil.setupLogHandler();
        
        final GMSPeerServer applicationServer;
        final GroupManagementService.MemberType memberType;

        if ("CORE".equals(System.getProperty("MEMBERTYPE", "CORE").toUpperCase())) {
            memberType = GroupManagementService.MemberType.CORE;
        } else {
            memberType = GroupManagementService.MemberType.SPECTATOR;
        }
        // TODO Configuration
        // TODO Move to ClusterConfig
        Properties configProps = new Properties();
        configProps.put(ServiceProviderConfigurationKeys.MULTICASTADDRESS.toString(),
                                    System.getProperty("MULTICASTADDRESS", "229.9.1.1"));
        configProps.put(ServiceProviderConfigurationKeys.MULTICASTPORT.toString(), 2299);
        logger.fine("Is initial host="+System.getProperty("IS_INITIAL_HOST"));
        configProps.put(ServiceProviderConfigurationKeys.IS_BOOTSTRAPPING_NODE.toString(),
                System.getProperty("IS_INITIAL_HOST", "false"));
        if(System.getProperty("INITIAL_HOST_LIST") != null){
            configProps.put(ServiceProviderConfigurationKeys.VIRTUAL_MULTICAST_URI_LIST.toString(),
                System.getProperty("INITIAL_HOST_LIST"));
        }
        configProps.put(ServiceProviderConfigurationKeys.FAILURE_DETECTION_RETRIES.toString(), "2");
        //Uncomment this to receive loop back messages
        configProps.put(ServiceProviderConfigurationKeys.LOOPBACK.toString(), "true");

        applicationServer = new GMSPeerServer(System.getProperty("INSTANCEID"), System.getProperty("CLUSTERNAME"), memberType, configProps);

        final Thread appServThread = new Thread(applicationServer, "ApplicationServer");
        appServThread.start();
        try {
            appServThread.join();
        } catch (InterruptedException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage());
        }
    }
    
    
}


